package com.sinothk.gpserver.modules.biz.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sinothk.gpserver.connection.websocket.WebSocketServer;
import com.sinothk.gpserver.connection.websocket.bean.RoomIM;
import com.sinothk.gpserver.data.WsConstant;
import com.sinothk.gpserver.modules.biz.entity.RoomEntity;
import com.sinothk.gpserver.modules.biz.entity.RoomVo;
import com.sinothk.gpserver.modules.biz.mapper.RoomMapper;
import com.sinothk.gpserver.modules.biz.service.IRoomService;
import com.sinothk.gpserver.modules.comm.serialNumber.service.SerialNumberService;
import com.sinothk.gpserver.modules.system.entity.LoginEntity;
import com.sinothk.gpserver.modules.system.entity.UserEntity;
import com.sinothk.gpserver.modules.system.mapper.UserMapper;
import com.sinothk.gpserver.util.DateUtils;
import com.sinothk.gpserver.util.PageDataUtil;
import com.sinothk.server.support.annotation.callback.BizException;
import com.sinothk.server.support.entity.PageData;
import com.sinothk.server.support.entity.PageVo;
import com.sinothk.server.support.utils.StringUtil;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>
 * 房间相关 服务实现类
 * </p>
 *
 * @author Liang Y.t.
 * @since 2021-08-30
 */
@Service
public class RoomServiceImpl extends ServiceImpl<RoomMapper, RoomEntity> implements IRoomService {

    @Resource
    private UserMapper userMapper;
    @Autowired
    private SerialNumberService snService;
    @Resource
    private RoomMapper roomMapper;

    /**
     * 查询分页数据
     *
     * @param pageVo 分页参数
     * @return PageData
     */
    @Override
    public PageData<RoomEntity> page(PageVo<RoomEntity> pageVo) {
        Page<RoomEntity> page = new Page<>(pageVo.getPageNum(), pageVo.getPageSize());
        IPage<RoomEntity> iPage = roomMapper.selectPage(page, null);
        return new PageDataUtil<RoomEntity>().create(iPage);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public RoomEntity create(RoomVo roomVo) {
        LoginEntity login = (LoginEntity) SecurityUtils.getSubject().getPrincipal();

        UserEntity user = userMapper.selectByAccount(login.getAccount());
        int roomCards = user.getRoomCards();
        int costCards = roomVo.getGameSize() / 5;
        if (roomCards < costCards)
            throw new BizException("房卡不足:需要" + roomVo.getGameSize() + "张, 但您只有" + roomCards + "张");
        user.setRoomCards(roomCards - costCards);
        userMapper.updateById(user);

        // 保存数据库
        RoomEntity room = new RoomEntity();
        BeanUtils.copyProperties(roomVo, room);
        room.setRoomLeaderAccount(login.getAccount());
        room.setRoomLeader(login.getUserName());
        room.setCreateBy(login.getAccount());
        room.setCreateTime(DateUtils.getLocalDateTime());

        String roomNum = snService.generateSerialNumberByModelCode("房间");
        room.setRoomNum(roomNum);
        this.save(room);

        // 房间创建后，创建IMRoom
        LambdaQueryWrapper<RoomEntity> roomWrapper = new LambdaQueryWrapper<>();
        roomWrapper.eq(RoomEntity::getRoomNum, roomNum);
        RoomEntity roomDb = this.getOne(roomWrapper);
        initImRoom(roomDb);
        return roomDb;
    }

    @Override
    public RoomEntity getRoomEntityByRoomNum(String roomNum) {
        LambdaQueryWrapper<RoomEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RoomEntity::getRoomNum, roomNum);
        return this.getOne(wrapper);
    }

    @Override
    public void initImRoom(RoomEntity roomEntity) {
        RoomIM roomIM = new RoomIM();
        BeanUtils.copyProperties(roomEntity, roomIM);
        roomIM.setGameTimes(0);
        roomIM.setBaseCoins(0);
        roomIM.setRoomCurrCast(0);
        roomIM.setState(WsConstant.ROOM_STATE.STATE_ROOM_READY);
        roomIM.setBigCast(roomEntity.getMinCast() * 2);
        roomIM.setCanSeeCard(false);
        //
        roomIM.setPlayers(new ConcurrentHashMap<>());
        roomIM.setVisitors(new ConcurrentHashMap<>());
        WebSocketServer.roomsMap.put(roomEntity.getRoomNum(), roomIM);

        log.debug(JSON.toJSONString("roomIM => " + JSON.toJSONString(roomIM)));
    }

    @Override
    public PageData<RoomEntity> pageForGroupMember(PageVo<RoomEntity> pageVo) {
        LoginEntity loginUser = (LoginEntity) SecurityUtils.getSubject().getPrincipal();

        Page<RoomEntity> page = new Page<>(pageVo.getPageNum(), pageVo.getPageSize());
        IPage<RoomEntity> iPage = roomMapper.pageForGroupMember(page, loginUser.getAccount());
        return new PageDataUtil<RoomEntity>().create(iPage);
    }

    @Override
    public PageData<RoomEntity> page7CardsForGroupMember(PageVo<RoomEntity> pageVo) {
        LoginEntity login = (LoginEntity) SecurityUtils.getSubject().getPrincipal();
        Page<RoomEntity> page = new Page<>(pageVo.getPageNum(), pageVo.getPageSize());
        IPage<RoomEntity> iPage = roomMapper.page7CardsForGroupMember(page, login.getAccount());
        return new PageDataUtil<RoomEntity>().create(iPage);
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public PageData<RoomEntity> pageForGroupId(PageVo<RoomEntity> pageVo) {
        if (pageVo == null || pageVo.getData() == null || StringUtil.isEmpty(pageVo.getData().getGroupId())) {
            throw new BizException("分页参数data没有必传值：groupId");
        }

        LambdaQueryWrapper<RoomEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RoomEntity::getGroupId, pageVo.getData().getGroupId());

        Page<RoomEntity> page = new Page<>(pageVo.getPageNum(), pageVo.getPageSize());
        IPage<RoomEntity> iPage = roomMapper.selectPage(page, wrapper);
        return new PageDataUtil<RoomEntity>().create(iPage);
    }

    @Override
    public RoomEntity retrieveByRoomNum(String roomNum) {
        LambdaQueryWrapper<RoomEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RoomEntity::getRoomNum, roomNum);

        RoomEntity room = this.getOne(wrapper);
        if (room == null) throw new BizException("房间不存在");
        return room;
    }

    @Override
    public void removeRoom(String roomNum) {
        LambdaQueryWrapper<RoomEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RoomEntity::getRoomNum, roomNum);
        this.remove(wrapper);
    }

    @Override
    public RoomEntity copy(String roomNum) {
        LambdaQueryWrapper<RoomEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RoomEntity::getRoomNum, roomNum);
        RoomEntity room = this.getOne(wrapper);
        if (room == null) throw new BizException("房间不存在");

        int num = new Random().nextInt(10000);
        String roomName = room.getRoomName();
        String roomNameNew = roomName;
        if (roomName.contains("_")) {
            roomNameNew = roomName.substring(0, roomName.lastIndexOf("_"));
        }
        room.setRoomName(roomNameNew + "_" + num);

        // 重置房间后，插入到表中
        room.setId(null);
        String roomNumNew = snService.generateSerialNumberByModelCode("房间");
        room.setRoomNum(roomNumNew);
        room.setGameTimes(0);
        room.setBaseCoins(0f);

        LoginEntity login = (LoginEntity) SecurityUtils.getSubject().getPrincipal();
        room.setCreateBy(login.getAccount());
        room.setCreateTime(DateUtils.getLocalDateTime());
        room.setDeleted(0);
        room.setState(0);

        this.save(room);

        RoomIM roomIM = new RoomIM();
        BeanUtils.copyProperties(room, roomIM);
        roomIM.setGameTimes(0);
        roomIM.setBaseCoins(0);
        roomIM.setRoomCurrCast(0);
        roomIM.setState(WsConstant.ROOM_STATE.STATE_ROOM_READY);
        roomIM.setBigCast(room.getMinCast() * 2);
        roomIM.setCanSeeCard(false);
        //
        roomIM.setPlayers(new ConcurrentHashMap<>());
        roomIM.setVisitors(new ConcurrentHashMap<>());
        WebSocketServer.roomsMap.put(room.getRoomNum(), roomIM);

        return room;
    }

}
